//
//  URL+SGExtension.swift
//  QingLiuSwift
//
//  Created by xyanl on 2024/12/12.
//  Copyright © 2024 考拉🐨. All rights reserved.
//

import UIKit

extension URL: SpadgerCompatible {}

// MARK: - 基本的扩展方法
public extension Spadger where Base == URL {
    
    /// 提取链接中的参数以字典形式显示
    /// let url = "http://zentao.dylan-saas.com/index.php?m=bug&f=browse&productid=1&branch=all&browseType=assigntome"
    /// 结果：["productid": "1", "browseType": "assigntome", "branch": "all", "m": "bug", "f": "browse"]
    var pathComponents: [String: String]? {
        guard let components = URLComponents(url: self.base, resolvingAgainstBaseURL: true), let queryItems = components.queryItems else {
            return nil
        }
        var parameters = [String: String]()
        for item in queryItems {
            parameters[item.name] = item.value
        }
        return parameters
    }
    
    /// 从url中获取后缀 例：mp3/mp4等等
    var pathExtension: String {
        return self.base.pathExtension.isEmpty ? "" : "\(self.base.pathExtension)"
    }
    
    /// 检测应用是否能打开这个URL
    var isCanOpenURL: Bool {
        UIApplication.shared.canOpenURL(self.base)
    }
    
    /// 属性说明
    func propertyDescription() {
        print("完整的url字符串 absoluteString：\(base.absoluteString)", "协议 scheme：\(base.scheme ?? "")", "域名 host：\(base.host ?? "")", "路径 path：\(base.path)", "相对路径 relativePath：\(base.relativePath)", "端口 port：\(base.port ?? 0)", "pathComponents：\(base.pathComponents)", "参数 query：\(base.query ?? "")")
    }
    
}


extension URL { /// 未测试
    /// Read Decodable extension attribute.
    func readDecodableExtendedAttribute<T: Decodable>(forName name: String, type: T.Type) throws -> T {
        let data = try readExtendedAttribute(forName: name)
        return try JSONDecoder().decode(T.self, from: data)
    }

    /// Set Encodable extension attribute.
    func setEncodableExtendedAttribute(value: some Encodable, forName name: String) throws {
        let data = try JSONEncoder().encode(value)
        try setExtendedAttribute(data: data, forName: name)
    }

    /// Get extended attribute.
    func readExtendedAttribute(forName name: String) throws -> Data {
        let data = try withUnsafeFileSystemRepresentation { fileSystemPath -> Data in
            // Determine attribute size:
            let length = getxattr(fileSystemPath, name, nil, 0, 0, 0)
            guard length >= 0 else { throw URL.posixError(errno) }
            // Create buffer with required size:
            var data = Data(count: length)
            // Retrieve attribute:
            let result = data.withUnsafeMutableBytes { [count = data.count] in
                getxattr(fileSystemPath, name, $0.baseAddress, count, 0, 0)
            }
            guard result >= 0 else { throw URL.posixError(errno) }
            return data
        }
        return data
    }

    /// Set extended attribute.
    func setExtendedAttribute(data: Data, forName name: String) throws {
        try withUnsafeFileSystemRepresentation { fileSystemPath in
            let result = data.withUnsafeBytes {
                setxattr(fileSystemPath, name, $0.baseAddress, data.count, 0, 0)
            }
            guard result >= 0 else { throw URL.posixError(errno) }
        }
    }

    /// Remove extended attribute.
    func removeExtendedAttribute(forName name: String) throws {
        try withUnsafeFileSystemRepresentation { fileSystemPath in
            let result = removexattr(fileSystemPath, name, 0)
            guard result >= 0 else { throw URL.posixError(errno) }
        }
    }

    /// Get list of all extended attributes.
    func listExtendedAttributes() throws -> [String] {
        let list = try withUnsafeFileSystemRepresentation { fileSystemPath -> [String] in
            let length = listxattr(fileSystemPath, nil, 0, 0)
            guard length >= 0 else { throw URL.posixError(errno) }
            // Create buffer with required size:
            var namebuf = [CChar](repeating: 0, count: length)
            // Retrieve attribute list:
            let result = listxattr(fileSystemPath, &namebuf, namebuf.count, 0)
            guard result >= 0 else { throw URL.posixError(errno) }
            // Extract attribute names:
            let list = namebuf.split(separator: 0).compactMap {
                $0.withUnsafeBufferPointer {
                    $0.withMemoryRebound(to: UInt8.self) {
                        String(bytes: $0, encoding: .utf8)
                    }
                }
            }
            return list
        }
        return list
    }

    /// Helper function to create an NSError from a Unix errno.
    private static func posixError(_ err: Int32) -> NSError {
        NSError(domain: NSPOSIXErrorDomain, code: Int(err), userInfo: [NSLocalizedDescriptionKey: String(cString: strerror(err))])
    }
}
